/*
* INSANE - Interactive Structural Analysis Environment
*
* Copyright (C) 2003-2005
* Universidade Federal de Minas Gerais
* Escola de Engenharia
* Departamento de Engenharia de Estruturas
* 
* Author's email :    insane@dees.ufmg.br
* Author's website :  http://www.dees.ufmg.br/insane
* 
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or any later version.
* 
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
* 
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/
package br.ufmg.dees.insane.model.disc.element;

import java.util.ArrayList;
import java.util.ListIterator;

import br.ufmg.dees.insane.model.disc.element.force.ElementForce;
import br.ufmg.dees.insane.model.disc.integrationorder.IntegrationOrder;
import br.ufmg.dees.insane.model.disc.integrationpoint.IntegrationPoint;
import br.ufmg.dees.insane.model.disc.node.Node;
import br.ufmg.dees.insane.model.disc.parametricintegration.ParametricIntegration;
import br.ufmg.dees.insane.model.disc.pointforce.PointForce;
import br.ufmg.dees.insane.util.IMatrix;
import br.ufmg.dees.insane.util.IVector;

/**
*A class representing a parametric element.<p>
*
*@author Lucas, Marcelo & Pitangueira, Roque
*@version 1.0
*@since June 2004
*/

public abstract class ParametricElement extends Element 
{
	
	private final static long serialVersionUID = 1L;
	
	/** The integration order of this ParametricElement.*/
	protected IntegrationOrder myIntegrationOrder;
	
	/** The Integration Points of this ParametricElement. */
	protected ArrayList<IntegrationPoint> integrationPoints = new ArrayList<IntegrationPoint>();
	
//********************************************************************************
	
	/** Generates Integration Points and theirs Weights factors of this ParametricElement. 
	*/
	public abstract void generateIntegrationPoints();
	
	/** Returns the nodal coordinates matrix of this Parametric Element
	*@return The nodal coordinates matrix.
	*/
	protected abstract IMatrix getNodesCoord();
	
	/** Return the ParametricIntegration object related to the line loads for this ParametricElement
	*@return  The ParametricIntegration object related to the line loads for this ParametricElement.
	*/
	public abstract ParametricIntegration getLineEqLoad();
	
	/** Return the ParametricIntegration object related to the area loads for this Element
	*@return  The ParametricIntegration object related to the area loads for this Element.
	*/
	protected abstract ParametricIntegration getAreaEqLoad();
	
	/** Return the ParametricIntegration object related to the volume loads for this Element
	*@return  The ParametricIntegration object related to the volume loads for this Element.
	*/
	protected abstract ParametricIntegration getVolumeEqLoad();
	
	/** Return the inverse of jacobian matrix.
	*@param a The jacobian matrix.
	*@return the inverse of jacobian matrix.
	*/
//	protected abstract IMatrix invertJacobian(IMatrix a);
	
	/** Return a ArrayList with PointForces representing the equivalent nodal load.
	*The utility of this method is receive the ParametricIntegration object and select its apropriated integration type method.
	*@return The ArrayList with PointForces representing the equivalent nodal load.
	*/
	protected abstract ArrayList getIntegralValues(ParametricIntegration a);
	
	/** Return the element integration coefficient
	*@return thickness * (1 or 1/2) for plane elements and (1 or 1/6) for solid elements. 
	*For bar elements returns the area of transversal section.
	*/
	protected abstract double getElmCoefficient();
	
//********************************************************************************
	
	public ParametricElement(){
	}
	
//********************************************************************************
	
	/** Sets the IntegrationOrder of this ParametricElement.
	*@param a The integrationOrder of this ParametricElement.
	*/
	public void setIntegrationOrder(IntegrationOrder a) {
		myIntegrationOrder = a;
	}
	
	/** Returns the integrationOrder of this ParametricElement.
	*@return The integrationOrder of this ParametricElement.
	*/	
	public IntegrationOrder getIntegrationOrder(){
		return(myIntegrationOrder);
	}
	
//********************************************************************************

	/** Return the number of degress of freedom of this ParametricElement.
	*@return The number of degrees of freedom.
	*/
	public int getNumberOfDegreesOfFreedom() {
		return((getIncidence().size())*(myAnalysisModel.getNdf()));
	}
	
//********************************************************************************

	/** Sets the node to this ParametricElement.
	*@param a A Node a in a specified position b.
	*@param b The position of the Node in the incidence.
	*/
	public void setNode(Node a, int b){
		if (incidence.size() != b) {
			incidence.remove(b);
			incidence.add(b, a);
		}
		else{
			incidence.add(a);
		}
	}
	
//********************************************************************************

	/** Returns the Node in a provided position.
	*@param a The position of the node in the nodes list named incidence.
	*/
	public Node getNode(int a){
		return ((Node)incidence.get(a));
	}
	

//********************************************************************************
	
	/** Return the global Stiffness Matrix of this ParametricElement.
	*/
	public IMatrix globalStiffnessMatrix(){
		int numberOfDegreesOfFreedom = this.getNumberOfDegreesOfFreedom();
		int dominion = myAnalysisModel.getDominion();
		
		IMatrix matrixD = myAnalysisModel.mountDMatrix((myMaterial.getPs()).toDoubleArray());
		IMatrix nodesCoord = this.getNodesCoord();
		IMatrix localDerivates = new IMatrix(dominion,(getIncidence().size()));
//		IMatrix invertJacobian = new IMatrix(dominion, dominion);
//		IMatrix globalDerivates = new IMatrix(dominion,(getIncidence().size()));
		IMatrix bMatrix;
		IMatrix jacobian;
		IMatrix k1 = new IMatrix(numberOfDegreesOfFreedom,matrixD.getNumCol());
		IMatrix stiffnessMatrix = new IMatrix(numberOfDegreesOfFreedom,numberOfDegreesOfFreedom);
		IMatrix finalStiffnessMatrix = new IMatrix(numberOfDegreesOfFreedom,numberOfDegreesOfFreedom);
		
		localDerivates.setZero();
//		jacobian.setZero();
//		invertJacobian.setZero();
//		globalDerivates.setZero();
		k1.setZero();
		stiffnessMatrix.setZero();
		finalStiffnessMatrix.setZero();
		
		IntegrationPoint integrationPoint;
		double[] integrationPointCoords;
		double integrationPointWeight;
		double intFactor = 1.0;
		double integrationCoef = 1.0;
		double detJacobian = 1.0;
		
		ListIterator ips = integrationPoints.listIterator();
		
int tam = integrationPoints.size();
System.out.println("tamanho da lista de pontos de Gauss :"+tam);
		
		while(ips.hasNext()) {
			integrationPoint = (IntegrationPoint) ips.next();
			integrationPointCoords = integrationPoint.getCoords();
			integrationPointWeight = integrationPoint.getWeights();
			intFactor = myAnalysisModel.getStiffnessFactor(myShape.getShapeFunction(integrationPointCoords), nodesCoord);
			localDerivates = myShape.getDerivedShapeFunction(integrationPointCoords);
			jacobian = myAnalysisModel.getJacobian(localDerivates,nodesCoord);
//			invertJacobian = this.invertJacobian(jacobian);
//			globalDerivates.mul(invertJacobian,localDerivates);
			bMatrix = myAnalysisModel.mountBMatrix(localDerivates, myShape.getShapeFunction(integrationPointCoords), nodesCoord);
//System.out.println("matriz B: "+bMatrix.getNumRow()+" x "+bMatrix.getNumCol());
			k1.mulTransposeLeft(bMatrix,matrixD);
			stiffnessMatrix.mul(k1,bMatrix);
			detJacobian = jacobian.determinantLU();
			//neste metodo getElmCoefficient estao incluidas espessura(elementos planos) ou area da secao transversal (elementos de barra).
			//para os elementos solidos este metodo retorna 1.0
			integrationCoef = ((integrationPointWeight)*(detJacobian)*(intFactor)*(this.getElmCoefficient()));
			stiffnessMatrix.setScale(integrationCoef);
			finalStiffnessMatrix.add(stiffnessMatrix);
		}
		return(finalStiffnessMatrix);
	}
	
//********************************************************************************
	
	/**Return the nodal displacements of this Paramentric Element.*/
	private double[] getDisplacements() {
		
		double[] elmNodeDisplacements = new double[(this.getNumberOfDegreesOfFreedom())];
		
		ListIterator nodes = incidence.listIterator();
		int j = 0;
		while(nodes.hasNext()) {
			Node node = (Node) nodes.next();
			
			for(int i=0; i<6; i++) {
				if(myAnalysisModel.getValidEquation(i))
				elmNodeDisplacements[i+j] = node.getDisplacement(i);
			}
			j = (j + myAnalysisModel.getNdf());
		}
		return(elmNodeDisplacements);
	}
	
//********************************************************************************
	
	/** Return the Stresses in a provided point.
	*@param a The array containing the tree coordinates of point.
	*@return sigma The IVector containing the stressses in a provided point
	*/
	public IVector getPointStress(double[] a) {
		IVector displ = new IVector(this.getDisplacements());
//		IMatrix invertJacobian = new IMatrix((myAnalysisModel.getDominion()), (myAnalysisModel.getDominion()));
//		IMatrix globalDerivates = new IMatrix((myAnalysisModel.getDominion()),(getIncidence().size()));
		IMatrix localDerivates;
		IMatrix nodesCoord;
//		IMatrix jacobian;
		IMatrix dTimesB;
		IMatrix DMatrix;
		IMatrix bMatrix;
		IVector sigma;
		
//		invertJacobian.setZero();
//		globalDerivates.setZero();
		
		DMatrix = myAnalysisModel.mountDMatrix((myMaterial.getPs()).toDoubleArray());
		nodesCoord = this.getNodesCoord();
		localDerivates = myShape.getDerivedShapeFunction(a);
//		jacobian = myAnalysisModel.getJacobian(localDerivates,nodesCoord);
//		invertJacobian = this.invertJacobian(jacobian);
//		globalDerivates.mul(invertJacobian,localDerivates);
		bMatrix = myAnalysisModel.mountBMatrix(localDerivates, myShape.getShapeFunction(a), nodesCoord);
		dTimesB = new IMatrix((bMatrix.getNumRow()), (this.getNumberOfDegreesOfFreedom()));
		sigma = new IVector(bMatrix.getNumRow());
		dTimesB.mul(DMatrix, bMatrix);
		sigma.mul(dTimesB, displ);
		
		return(sigma);
	}
	
//********************************************************************************
	/** Return the Stresses in a provided point.
	*@param a The array containing the tree coordinates of point.
	*@return sigma The IVector containing the stressses in a provided point
	*/
	public IVector getPointStress(IntegrationPoint ip) {
		IVector epsilon = this.getPointStrain(ip);
		IMatrix DMatrix = myAnalysisModel.mountDMatrix(ip.getEMatrix(epsilon));	//getEMatrix ainda n�o implementado em ip
		IVector sigma = new IVector(epsilon.getSize());
        sigma.mul(DMatrix, epsilon);
		return(sigma);
	}
	
//	********************************************************************************	
	/** Return the Strain in a provided point.
	*@param a The array containing the tree coordinates of point.
	*@return sigma The IVector containing the stressses in a provided point
	*/
	public IVector getPointStrain(double[] a) {
		IVector displ = new IVector(this.getDisplacements());
		IMatrix localDerivates;
		IMatrix nodesCoord;
		IMatrix bMatrix;
		IVector epsilon;	
		nodesCoord = this.getNodesCoord();
		localDerivates = myShape.getDerivedShapeFunction(a);
		bMatrix = myAnalysisModel.mountBMatrix(localDerivates, myShape.getShapeFunction(a), nodesCoord);
		epsilon = new IVector(bMatrix.getNumRow());
		epsilon.mul(bMatrix, displ);
		return(epsilon);
	}
	
//	********************************************************************************
	/** Return the Strain in a provided point.
	*@param a The array containing the tree coordinates of point.
	*@return sigma The IVector containing the stressses in a provided point
	*/
	public IVector getPointStrain(IntegrationPoint ip) {
		IVector displ = new IVector(this.getDisplacements());
		IMatrix bMatrix = this.getBMatrix(ip);
		IVector epsilon = new IVector(bMatrix.getNumRow());
        epsilon.mul(bMatrix, displ);
		return(epsilon);
	}
	
//	********************************************************************************
	/** Return the Strain in a provided point.
	*@param a The array containing the tree coordinates of point.
	*@return sigma The IVector containing the stressses in a provided point
	*/
	public IMatrix getBMatrix(IntegrationPoint ip) {
		//IVector displ = new IVector(this.getDisplacements());
		IMatrix localDerivates;
		IMatrix nodesCoord;
		IMatrix bMatrix;
		nodesCoord = this.getNodesCoord();
		localDerivates = myShape.getDerivedShapeFunction(ip.getCoords());
		bMatrix = myAnalysisModel.mountBMatrix(localDerivates, myShape.getShapeFunction(ip.getCoords()), nodesCoord);
		return(bMatrix);
	}
//  ********************************************************************************
    
    /** Return the Strain in a provided point.
    *@param a The array containing the tree coordinates of point.
    *@return sigma The IVector containing the stressses in a provided point
    */
    public IMatrix getJacobian(IntegrationPoint ip) {
        
        int dominion = myAnalysisModel.getDominion();
        IMatrix nodesCoord = this.getNodesCoord();
        IMatrix localDerivates = new IMatrix(dominion,(getIncidence().size()));
        IMatrix jacobian;
        
        localDerivates.setZero();        
        localDerivates = myShape.getDerivedShapeFunction(ip.getCoords());
        jacobian = myAnalysisModel.getJacobian(localDerivates,nodesCoord);
        return jacobian;
     }
//********************************************************************************
	/** Return the array containing the stresses in all integration points. 
	*@return ipStresses The active strees in all integrationPoints.
	*/
	public double[][] getIntegrationPointsStresses(){
		IntegrationPoint integrationPoint;
				
		double[][] ipStresses = new double[integrationPoints.size()][(myAnalysisModel.getNumberOfActiveStress())];
		
		ListIterator ipts = integrationPoints.listIterator();
		int i = 0;
		while(ipts.hasNext()){
			integrationPoint = (IntegrationPoint) ipts.next();
			for(int j = 0; j < (myAnalysisModel.getNumberOfActiveStress()); j++){
				ipStresses[i][j] = (double)(this.getPointStress(integrationPoint.getCoords())).getElement(j);
			}
			i++;
		}
		return ipStresses;
	}
	
//********************************************************************************
	
	/** Return the IMatrix containing the stresses in all element nodes.
	*This method places all stresses at each node in one column of output matrix.
	*@return nodeStresses The stresses in all element nodes.
	*/
	public IMatrix getNodalPointStress(){
		IMatrix natCoords;
		IMatrix nodalStresses;
		double[] nodeCoord;
		
		natCoords = myShape.getNaturalNodalCoords();
		nodalStresses = new IMatrix(myAnalysisModel.getNumberOfActiveStress(), natCoords.getNumCol());
		nodeCoord = new double[natCoords.getNumRow()];
		
		for(int i = 0; i < natCoords.getNumCol(); i++)//este for e para percorrer todos os pontos nodais
		{
			for(int j = 0; j < natCoords.getNumRow(); j++)//este for e para percorrer as coordeandas xi, eta, zeta.
			{
				nodeCoord[j] = natCoords.getElement(j,i);
			}
			nodalStresses.setColumn(i, myAnalysisModel.getStressVector(this.getPointStress(nodeCoord),(this.getMaterial())));
		}
			return nodalStresses;
	}

//********************************************************************************
	
	/** Return the IMatrix containing the strains in all element nodes.
	*This method places all strains at each node in one column of output matrix.
	*@return nodeStrains The strains in all element nodes.
	*/
	public IMatrix getNodalPointStrains() {
		IMatrix natCoords;
		IMatrix nodalStrains;
		double[] nodeCoord;
		
		natCoords = myShape.getNaturalNodalCoords();
		nodalStrains = new IMatrix(myAnalysisModel.getNumberOfActiveStrains(), natCoords.getNumCol());
		nodeCoord = new double[natCoords.getNumRow()];
		
		for(int i = 0; i < natCoords.getNumCol(); i++)//este for e para percorrer todos os pontos nodais
		{
			for(int j = 0; j < natCoords.getNumRow(); j++)//este for e para percorrer as coordeandas xi, eta, zeta.
			{
				nodeCoord[j] = natCoords.getElement(j,i);
			}
			nodalStrains.setColumn(i, myAnalysisModel.getStrainVector(this.getPointStrains(nodeCoord),(this.getMaterial())));
		}
			return nodalStrains;
	}

//********************************************************************************

	/** Return the list of integrationPoints of this Parametric Element.
	*@return integrationPoints The arraylist with all integration points of this Parametric Element.
	*/
	public ArrayList getIntegrationPointsList()	{
		return integrationPoints;
	}

//********************************************************************************
	
	/** Return the Strains related to the provided stresses.
	*@param a The array containing the tree coordinates of point.
	*@return epslon The array containing the strains in a provided point
	*/
	public IVector getPointStrains(double[] a)	{
		IVector displ = new IVector(this.getDisplacements());
		IMatrix localDerivates = new IMatrix((myAnalysisModel.getDominion()),(getIncidence().size()));
//		IMatrix invertJacobian = new IMatrix((myAnalysisModel.getDominion()), (myAnalysisModel.getDominion()));
//		IMatrix globalDerivates = new IMatrix((myAnalysisModel.getDominion()),(getIncidence().size()));
		IMatrix nodesCoord;
//		IMatrix jacobian;
		IMatrix bMatrix;
		IVector epslon;
		
		localDerivates.setZero();
//		invertJacobian.setZero();
//		globalDerivates.setZero();
		
		nodesCoord = this.getNodesCoord();
		localDerivates = myShape.getDerivedShapeFunction(a);
//		jacobian = myAnalysisModel.getJacobian(localDerivates,nodesCoord);
//		invertJacobian = this.invertJacobian(jacobian);
//		globalDerivates.mul(invertJacobian,localDerivates);
		bMatrix = myAnalysisModel.mountBMatrix(localDerivates, myShape.getShapeFunction(a), nodesCoord);
		epslon = new IVector(bMatrix.getNumRow());
		epslon.mul(bMatrix, displ);
		
		return(epslon);
	}
	
//********************************************************************************
		
	/** Adds PointForces to equivNLoad List coherently with element incidence.
	*@param a The List of PointForces to be added.
	*/
	//private void addEquivNLoadInOrder(ArrayList a){
		/*
		Node node;
		PointForce pf;
		
		ListIterator pfs = a.listIterator();
		while(pfs.hasNext()){
			pf = (PointForce) pfs.next();
			ListIterator nodes = this.getIncidence().listIterator();
			int i = 0;
			while(nodes.hasNext())	{
				node = (Node) nodes.next();
				if(((pf.getCoord()).x == (node.getCoord()).x) && ((pf.getCoord()).y == (node.getCoord()).y) && ((pf.getCoord()).z == (node.getCoord()).z))
				{
//System.out.println("numero do no: "+node.getLabel());
					this.addEquivNLoad(i, pf);
				}
//System.out.println("posicao no arrayList: "+i);
				i++;
			}
		}*/
	//}
	
//********************************************************************************
	
	/** Mount the equivalent nodal load of this Parametric Element, addind to equivNLoad ArrayList of the Element.
	*/
	//public void mountEquivNodalLoad()	{
		/*
		ElementForce ef;
		PointForce pf;
		ParametricIntegration parIn;
		this.fillEquivNLoad();
		
		//LineForces
		if(this.getElmLineForcesList().size() != 0)//verifica se a variavel elmLineForce esta vazia
		{
			ListIterator lineforces = this.getElmLineForcesList().listIterator();
			while(lineforces.hasNext())	{
				
				ef = (ElementForce) lineforces.next();
				parIn = this.getLineEqLoad();//este metodo retorna o tipo apropriado de parIn
				ListIterator pfs = ef.getPointForcesList().listIterator();
				while(pfs.hasNext()){
					pf = (PointForce) pfs.next();
					parIn.add(pf);//adiciona o pointforce na lista de parIn
				}
				this.addEquivNLoadInOrder(this.getIntegralValues(parIn));//parIn.getIntegralF() calcula carregamento nodal equivalente e
				//this.getIntegralValues(parIn) passa o objeto ParametricIntegration para o proprio elemento que sabera qual metodo chamar 
				//de parIn para calcular o carregamento nodal equivalente.
				//this.addToEquivNLoad(ArrayList a) adiciona apropriadamente a variavel arrayList do elemento chamada equivNLoad
			}
		}
		
		//SurfaceForces
		if(this.getElmSurfaceForcesList().size() != 0)	{
			ListIterator surfaceforces = this.getElmSurfaceForcesList().listIterator();
			while(surfaceforces.hasNext()){
				ef = (ElementForce) surfaceforces.next();
				parIn = this.getAreaEqLoad();
				ListIterator pfs = ef.getPointForcesList().listIterator();
				while(pfs.hasNext()){
					pf = (PointForce) pfs.next();
					parIn.add(pf);
				}
					this.addEquivNLoadInOrder(this.getIntegralValues(parIn));//parIn.getIntegralF() calcula carregamento nodal equivalente e
					//this.addToEquivNLoad(ArrayList a) adiciona apropriadamente a variavel arrayList do elemento chamada equivNLoad
			}
		}
		
		//BodyForces
		if(this.getElmBodyForcesList().size() != 0)	{
			ListIterator bodyforces = this.getElmBodyForcesList().listIterator();
			while(bodyforces.hasNext())	{
				ef = (ElementForce) bodyforces.next();
				parIn = this.getVolumeEqLoad();
				ListIterator pfs = ef.getPointForcesList().listIterator();
				while(pfs.hasNext()){
					pf = (PointForce) pfs.next();
					parIn.add(pf);
				}
				this.addEquivNLoadInOrder(parIn.getIntegralF());
			}
		}*/
	//}
	
//********************************************************************************
	
	/** Fill the equivNLoad ArrayList of this Parametric Element with PointForces
	*/
	/*private void fillEquivNLoad(){
		PointForce pf;
		for(int i = 0; i < (this.getIncidence().size()); i++) {
			pf = new PointForce();
			equivNLoad.add(pf);
		}
	}*/
	
//********************************************************************************
	
	/** Returns the ElementForce in the specified position of the ElmLineForcesList of this Element.
	*@param a The position of the ElementForce desired in the ElmLineForcesList.
	*@return The ElementForce in the specified position of the ElmLineForcesList of this Element.
	*/
	/*private ElementForce getElmLineElementForce(int a)	{
		return ((ElementForce) elmLineForces.get(a));
	}*/
	
	/** Returns the ElementForce with the specified label.
	*@param a The label of the ElementForce desired.
	*@return The ElementForce with the specified label.
	*/
	/*private ElementForce getElmLineElementForce(String a){
		ElementForce ef;
		ListIterator efs = elmLineForces.listIterator();
		while (efs.hasNext()){
			ef = (ElementForce) efs.next();
			if (ef.getLabel() == a)	{
				return (ef);
			}
		}
		return (null);
	}*/
	
	/** Adds the specified ElementForce to the ElmLineForcesList.
	*@param a The ElementForce to be added to the ElmLineForcesList.
	*/
	/*public void addElmLineForce(ElementForce a) {
		elmLineForces.add(a);
	}*/
	
//********************************************************************************
	
	/** Returns the elmSurfaceForcesList of this Element.
	*@return The elmSurfaceForcesList of this Element.
	*/
	/*private ArrayList getElmSurfaceForcesList() {
		return (elmSurfaceForces);
	}*/
	
	/** Sets the ElmSurfaceForcesList of this Element.
	*@param a The ElmSurfaceForcesList of this Element.
	*/
	/*private void setElmSurfaceForcesList(ArrayList a){
		elmSurfaceForces = a;
	}*/
	
	/** Returns the ElementForce in the specified position of the ElmSurfaceForcesList of this Element.
	*@param a The position of the ElementForce desired in the ElmSurfaceForcesList.
	*@return The ElementForce in the specified position of the ElmSurfaceForcesList of this Element.
	*/
	/*private ElementForce getElmSurfaceElementForce(int a){
		return ((ElementForce) elmSurfaceForces.get(a));
	}*/
	
	/** Returns the ElementForce with the specified label.
	*@param a The label of the ElementForce desired.
	*@return The ElementForce with the specified label.
	*/
	/*private ElementForce getElmSurfaceElementForce(String a){
		ElementForce ef;
		ListIterator efs = elmSurfaceForces.listIterator();
		while (efs.hasNext()){
			ef = (ElementForce) efs.next();
			if (ef.getLabel() == a)	{
				return (ef);
			}
		}
		return (null);
	}*/
	
	/** Adds the specified ElementForce to the ElmSurfaceForcesList.
	*@param a The ElementForce to be added to the ElmSurfaceForcesList.
	*/
	/*public void addElmSurfaceForce(ElementForce a) {
		elmSurfaceForces.add(a);
	}*/
	
//********************************************************************************
	
	/** Returns the elmBodyForcesList of this Element.
	*@return The elmBodyForcesList of this Element.
	*/
	/*private ArrayList getElmBodyForcesList() {
		return (elmBodyForces);
	}*/
	
	/** Sets the ElmBodyForcesList of this Element.
	*@param a The ElmBodyForcesList of this Element.
	*/
	/*private void setElmBodyForcesList(ArrayList a) {
		elmBodyForces = a;
	}*/
	
	/** Returns the ElementForce in the specified position of the ElmBodyForcesList of this Element.
	*@param a The position of the ElementForce desired in the ElmBodyForcesList.
	*@return The ElementForce in the specified position of the ElmBodyForcesList of this Element.
	*/
	/*private ElementForce getElmBodyElementForce(int a) {
		return ((ElementForce) elmBodyForces.get(a));
	}*/
	
	/** Returns the ElementForce with the specified label.
	*@param a The label of the ElementForce desired.
	*@return The ElementForce with the specified label.
	*/
	/*private ElementForce getElmBodyElementForce(String a) {
		ElementForce ef;
		ListIterator efs = elmBodyForces.listIterator();
		while (efs.hasNext()) {
			ef = (ElementForce) efs.next();
			if (ef.getLabel() == a)	{
				return (ef);
			}
		}
		return (null);
	}
	
	/** Adds the specified ElementForce to the ElmBodyForcesList.
	*@param a The ElementForce to be added to the ElmBodyForcesList.
	*/
	/*public void addElmBodyForce(ElementForce a) {
		elmBodyForces.add(a);
	}*/
	
//********************************************************************************
	
	/** Returns the EquivNLoadList of this Element.
	*@return The EquivNLoadList of this Element.
	*/
	/*private ArrayList getEquivNLoadList() {
		return (equivNLoad);
	}*/
	
	/** Sets the EquivNLoadList of this Element.
	*@param a The EquivNLoadList of this Element.
	*/
	/*private void setEquivNLoadList(ArrayList a) {
		equivNLoad = a;
	}*/
	
	/** Returns the PointForce on this Element in the specified position of the EquivNLoadList of this Element.
	*@param a The position of the PointForce desired in the EquivNLoadList.
	*@return The PointForce on this Element in the specified position of the EquivNLoadList of this Element.
	*/
	/*public PointForce getEquivNLoad(int a) {
		return ((PointForce) equivNLoad.get(a));
	}*/
	
	/** Returns the PointForce on this Element with the specified label.
	*@param a The PointForce on this Element with the specified label.
	*@return The PointForce on this Element with the specified label.
	*/
	/*private PointForce getEquivNLoad(String a) {
		PointForce pf;
		ListIterator pfs = equivNLoad.listIterator();
		while (pfs.hasNext()) {
			pf = (PointForce) pfs.next();
			if (pf.getLabel() == a) {
				return (pf);
			}
		}
		return (null);
	}*/
	
	/** Adds the specified PointForce to the equivNLoadList.
	*@param a The position in the equivNLoadList that be added.
	*@param b The PointForce to be added to the equivNLoadList.
	*/
	/*private void addEquivNLoad(int a, PointForce b) {
		PointForce pf;
		pf = (PointForce) equivNLoad.get(a);
		pf.addForce(b.getForces());
		
//		equivNLoad.add(a, pf);
	}*/

//********************************************************************************
	
	/** Returns the reduced equivalent nodal force vector of this Element in the global coords.
	*@return The reduced equivalent nodal force vector of this Element in the global coords.
	*/
	public IVector globalEquivalentForceVector()
	{
		ArrayList<PointForce> equivNLoad = new ArrayList<PointForce>();
		ElementForce ef;
		PointForce pf;
		ParametricIntegration parIn;
		
		//Filling equivNLoad;
		PointForce enli;//enli representa o PointForce relacionado ao no i da lista de nos do elemento;
		for(int i = 0; i < (this.getIncidence().size()); i++)
		{
			enli = new PointForce();
			equivNLoad.add(enli);
		}
		
		//LineForces
		if(this.getElmLineForcesList().size() != 0)//verifica se a variavel elmLineForce esta vazia
		{
			ListIterator lineforces = this.getElmLineForcesList().listIterator();
			while(lineforces.hasNext())
			{
				ef = (ElementForce) lineforces.next();
				parIn = this.getLineEqLoad();//este metodo retorna o tipo apropriado de parIn
				ListIterator pfs = ef.getPointForcesList().listIterator();
				while(pfs.hasNext())
				{
					pf = (PointForce) pfs.next();
					parIn.add(pf);//adiciona o pointforce na lista de parIn
				}

//parIn.getIntegralF() calcula carregamento nodal equivalente e
//this.getIntegralValues(parIn) passa o objeto ParametricIntegration para o proprio elemento que sabera qual metodo chamar 
//de parIn para calcular o carregamento nodal equivalente.
				ArrayList a = this.getIntegralValues(parIn);
				Node node;
				PointForce pf3;
				ListIterator enlis = a.listIterator();
				while(enlis.hasNext())
				{
					pf3 = (PointForce) enlis.next();
					ListIterator nodes = this.getIncidence().listIterator();
					int i = 0;
					while(nodes.hasNext())
					{
						node = (Node) nodes.next();
						if(((pf3.getCoord()).x == (node.getCoord()).x) && ((pf3.getCoord()).y == (node.getCoord()).y) && ((pf3.getCoord()).z == (node.getCoord()).z))
						{
							PointForce pf4;
							pf4 = (PointForce) equivNLoad.get(i);
							pf4.addForce(pf3.getForces());
						}
						i++;
					}
				}
			}
		}
		
		//SurfaceForces
		if(this.getElmSurfaceForcesList().size() != 0)
		{
			ListIterator surfaceforces = this.getElmSurfaceForcesList().listIterator();
			while(surfaceforces.hasNext())
			{
				ef = (ElementForce) surfaceforces.next();
					parIn = this.getAreaEqLoad();
				ListIterator pfs = ef.getPointForcesList().listIterator();
				while(pfs.hasNext())
				{
					pf = (PointForce) pfs.next();
					parIn.add(pf);
				}
				
				ArrayList a = getIntegralValues(parIn);
				Node node;
				PointForce pf3;
				ListIterator pfs2 = a.listIterator();
				while(pfs2.hasNext()){
					pf3 = (PointForce) pfs2.next();
					ListIterator nodes = this.getIncidence().listIterator();
					int i = 0;
					while(nodes.hasNext())	{
						node = (Node) nodes.next();
						if(((pf3.getCoord()).x == (node.getCoord()).x) && ((pf3.getCoord()).y == (node.getCoord()).y) && ((pf3.getCoord()).z == (node.getCoord()).z))
						{
							PointForce pf4;
							pf4 = (PointForce) equivNLoad.get(i);
							pf4.addForce(pf3.getForces());
							
						}
						i++;
					}
				}
				
			}
		}
		
		//VolumeForces
		if(this.getElmVolumeForcesList().size() != 0)
		{
			ListIterator volumeforces = this.getElmVolumeForcesList().listIterator();
				while(volumeforces.hasNext())
			{
				ef = (ElementForce) volumeforces.next();
				parIn = this.getVolumeEqLoad();
				ListIterator pfs = ef.getPointForcesList().listIterator();
				while(pfs.hasNext())
					{
					pf = (PointForce) pfs.next();
					parIn.add(pf);
				}
				
				ArrayList a = parIn.getIntegralF();
				Node node;
				PointForce pf3;
				ListIterator pfs2 = a.listIterator();
				while(pfs2.hasNext()){
					pf3 = (PointForce) pfs2.next();
					ListIterator nodes = this.getIncidence().listIterator();
					int i = 0;
					while(nodes.hasNext())	{
						node = (Node) nodes.next();
						if(((pf3.getCoord()).x == (node.getCoord()).x) && ((pf3.getCoord()).y == (node.getCoord()).y) && ((pf3.getCoord()).z == (node.getCoord()).z))
						{
							PointForce pf4;
							pf4 = (PointForce) equivNLoad.get(i);
							pf4.addForce(pf3.getForces());
							
						}
						i++;
					}
				}
			}
		}
		
		//Reducing Equivalent Force Vector
		IVector equivF = new IVector(this.getIncidence().size()*myAnalysisModel.getNdf());
		equivF.zero();
		ListIterator nodes = this.getIncidence().listIterator();
		int i = 0;
		int k = 0;
		while(nodes.hasNext())
		{
			nodes.next();
			for(int j = 0; j < 6; j++)
			{
				if(myAnalysisModel.getValidEquation(j))
				{
					equivF.setElement(k, (((PointForce)equivNLoad.get(i)).getForce(j)));
					k++;
				}
			}
			i++;
		}
		return equivF;
	}
	
//********************************************************************************
	
	public IVector internalForces(){
		
			int numberOfDegreesOfFreedom = this.getNumberOfDegreesOfFreedom();
						
			IMatrix nodesCoord = this.getNodesCoord();
			IMatrix bMatrix;
			IMatrix jacobian;
			
			IVector internalForce = new IVector(numberOfDegreesOfFreedom);
			
			internalForce.zero();
			
			IntegrationPoint integrationPoint;
			double[] integrationPointCoords;
			double integrationPointWeight;
			double intFactor = 1.0;
			double integrationCoef = 1.0;
			double detJacobian = 1.0;
							
			ListIterator ips = integrationPoints.listIterator();
			while(ips.hasNext()) {
				integrationPoint = (IntegrationPoint) ips.next();
				IVector f = new IVector(numberOfDegreesOfFreedom);
				integrationPointCoords = integrationPoint.getCoords();	
				integrationPointWeight = integrationPoint.getWeights();
				intFactor = myAnalysisModel.getStiffnessFactor(myShape.getShapeFunction(integrationPointCoords), nodesCoord);
				jacobian =this.getJacobian(integrationPoint);
				
				bMatrix = this.getBMatrix(integrationPoint);
                bMatrix.transpose();
				f.mul(bMatrix,this.getPointStress(integrationPoint));
				detJacobian = jacobian.determinantLU();
				integrationCoef = ((integrationPointWeight)*(detJacobian)*(intFactor)*(this.getElmCoefficient()));
				f.scale(integrationCoef);
				internalForce.add(f);
			}
			return internalForce;	
	}

//********************************************************************************
	
	public void printMatrix(IMatrix a) {
		for (int i = 0; i < a.getNumRow(); i++) {
			System.out.println();
			for (int j = 0; j < a.getNumCol(); j++) {
				System.out.print(a.getElement(i, j));
				System.out.print("\t");
			}
		}
		//System.out.println("TAMANHO DA MATRIZ: "+a.getNumRow()+" x "+a.getNumCol());
	}
	
	public void printVector(IVector a) {
		for (int i=0; i<a.getSize(); i++) {
			System.out.println();
			System.out.print(a.getElement(i));
			System.out.print("\t");
		}
		//System.out.println("TAMANHO DO VETOR: "+a.getSize());
	}
	
//********************************************************************************
	
	public IMatrix mountN(IntegrationPoint ip){
		
	    IMatrix N = new IMatrix(0,0);
		N = this.getAnalysisModel().mountMatrixN(this.getShape().getShapeFunction(ip.getCoords()));
        return N;
	}
	
	public IMatrix mountN(){
		
	    IMatrix N = new IMatrix(0,0);
		ListIterator ElmGaussPts = this.getIntegrationPointsList().listIterator();
		while (ElmGaussPts.hasNext()){
			IntegrationPoint ip = (IntegrationPoint)ElmGaussPts.next();
			System.out.println("ip"+ip);
			N = this.getAnalysisModel().mountMatrixN(this.getShape().getShapeFunction(ip.getCoords()));
			System.out.println("this.getShape()"+this.getShape());
			System.out.println("getShapeFunction(ip.getCoords())"+this.getShape().getShapeFunction(ip.getCoords()));
		}
		
		System.out.println("mountN"+N);
        return N;
	}
	
//	********************************************************************************
	
	public IVector mountCoords(){
	    IVector coords = new IVector(this.getAnalysisModel().getNdf()*this.getIncidence().size());
	    ListIterator nodes = this.getIncidence().listIterator();
		int cont = 0;
		while(nodes.hasNext()){
			Node no = (Node)nodes.next();
			coords.setElement(cont,no.getCoord().x);
			cont++;
			coords.setElement(cont,no.getCoord().y);
			cont++;
		}
		return coords;
	}
//	********************************************************************************
	
	
}

